home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / misc / pclta-1.000 / pclta-1 / pclta / pclta.c < prev   
Encoding:
C/C++ Source or Header  |  1996-04-03  |  14.7 KB  |  551 lines

  1. /* pclta.c: Device driver for PCLTA and PCNSS LON-interface cards */
  2. /*
  3.     Written 1996 by Miran Miksic.
  4.     Copyright 1996 Miran Miksic
  5.     Copyright 1996 Fastec GmbH
  6.  
  7.     The author may be reached as mmiksic@hni.uni-paderborn.de.
  8.     Heinz Nixdorf Institut, Universitaet GH Paderborn
  9.     Fuerstenallee 11, 33102 Paderborn, Germany
  10.  
  11.     This very first version works only with the A-channel when dealing
  12.     with PCLTA card. In the future, the minor number should determine
  13.     the channel type.
  14.  
  15.     Default base IO address is 0x200, which can be changed with
  16.     base_io=<base_io_address> when loading the module. The default major
  17.     number is 40 and can be also changed with major=<major_number>.
  18.     To access a device, a special character file with coresponding
  19.     major number must be created. Minor number is at the time irelevant.
  20.  
  21.     There is an interrupt support on the card, but it's in this version
  22.     not used. To increase efficiency, an interrupt-driven system should be
  23.     implemented in the future.
  24.  
  25.     A better distinguishement between PCNSS and PCLTA card should also be
  26.     implemented. But, I'm not in possesion of the full documentation for the
  27.     PCNSS card, and I have a document for a NSS-10 module for only two days.
  28.  
  29.     gcc: 2.7.2
  30.     kernel: 1.3.79
  31.     modules: 1.3.57
  32.  
  33.     Revision: 1.9
  34.     RCS: pclta.c,v 1.9 1996/04/03 11:32:52 miksic Exp
  35. */
  36.  
  37. static char *version =
  38.     "pclta.c: pclta and pcnss driver v1.9 1996/04/03 11:32:52\n"
  39.     "Copyright 1996 Miran Miksic (mmiksic@hni.uni-paderborn.de)\n";
  40.  
  41. #include <linux/config.h>
  42.     /* include the configuration header file, to be certain that a module
  43.      * is compiled together with the actual version of kernel */
  44.  
  45. #if defined MODULE
  46. #include <linux/module.h>
  47. #include <linux/version.h>
  48. #else
  49. #define MOD_INC_USE_COUNT
  50. #define MOD_DEC_USE_COUNT
  51. #endif
  52.     /* include module and version headers */
  53.  
  54. #include <linux/mm.h> /* for verify_area() */
  55. #include <linux/ioport.h> /* for *_region() */
  56. #include <asm/io.h> /* for in*(), out*() */
  57.  
  58. #define SLEEPENG        0x20
  59. #define DLPBA            0x10
  60. #define DLBA            0x08
  61. #define ULREADY            0x04
  62. #define RESET            0x02
  63. #define _READY            0x01
  64. #define CLRIRQ            0x01
  65. #define _RESET            0x10
  66. #define IRQ15            0x20
  67. #define IRQ12            0x10
  68. #define IRQ11            0x08
  69. #define IRQ10            0x04
  70. #define IRQ9            0x02
  71. #define IRQ5            0x01
  72. #define CLK_10            0x00
  73. #define CLK_5            0x01
  74. #define CLK_2_5            0x02
  75. #define CLK_1_25        0x03
  76. #define CLK_0_625        0x04
  77. #define BATTERY            0x03
  78. #define IRQPLRTY        0x80
  79. #define RESETE            0x40
  80. #define DLREADYE        0x20
  81. #define DLPBAE            0x10
  82. #define DLBAE            0x08
  83. #define ULREADYE        0x04
  84.     /* masks for bitfields according to pcpclta definitions */
  85.  
  86. #define CMD_XFER        0x01
  87. #define CMD_ACK            0x02
  88.     /* control bytes to transfer according to the protocol */
  89.  
  90. #define data_reg        (base_io)    /* input/output */
  91. #define status_reg        (base_io+1)    /* input */
  92. #define clrirq_reg        (base_io+1)    /* output */
  93. #define selirq_reg        (base_io+2)    /* output */
  94. #define clkrst_reg        (base_io+3)    /* output */
  95.     /* register names */
  96.  
  97. #define TIMER_SLEEP        0x00
  98. #define TIMER_TIMEOUT        0x01
  99.     /* kinds of timer events */
  100.  
  101. #define NI_Q_CMD        0xf0
  102. #define NI_QUEUE        0x0f
  103.     /* masks to get network command and network buffer */
  104.  
  105. #define niCOMM            0x10
  106. #define niNETMGMT        0x20
  107.     /* network interface commands that need the
  108.      * output buffer avaiable */
  109.  
  110. #define niRESET            0x50
  111. #define niFLUSH_CANCEL        0x60
  112. #define niFLUSH_COMPLETE    0x60
  113. #define niONLINE        0x70
  114. #define niOFFLINE        0x80
  115. #define niFLUSH            0x90
  116. #define niFLUSH_IGN        0xA0
  117. #define niSLEEP            0xB0
  118. #define niSSTATUS        0xE0
  119. #define niIRQENA        0xE5
  120. #define niSERVICE        0xE6
  121.     /* network interface commands that do not
  122.      * need the output buffer avaiable */
  123.  
  124. #define niTQ            0x02
  125. #define niTQ_P            0x03
  126. #define niNTQ            0x04
  127. #define niNTQ_P            0x05
  128.     /* output queues */
  129.  
  130. #define niRESPONSE        0x06
  131. #define niINCOMING        0x08
  132.     /* input queues */
  133.  
  134. #if !defined MODULE
  135. long int pclta_init( long mem_start, long mem_end );
  136. #endif
  137.     /* the function to init module when compiled
  138.      * directly to kernel */
  139.  
  140. int init_module( void );
  141.     /* the real function to init module; when the module is compiled
  142.      * directly to kernel, this function is called from pclta_init() */
  143.  
  144. #if defined MODULE
  145. void cleanup_module( void );
  146. #endif
  147.     /* the function to clean the module from kernel when it's
  148.      * loaded dynamically */
  149.  
  150. static int read_pclta( struct inode *inode, struct file *file, char *buf, int count );
  151. static int write_pclta( struct inode *inode, struct file *file, const char *buf, int count );
  152.     /* read/write functions */
  153.  
  154. static int open_pclta( struct inode *node, struct file *file );
  155. static void close_pclta( struct inode *node, struct file *file );
  156.     /* open/close functions */
  157.  
  158. static unsigned char read_byte_wait( void );
  159. static void write_byte_wait( unsigned char byte );
  160.     /* read/write single byte, then
  161.      * poll status register until ready */
  162.  
  163. static int write_byte_timeout( unsigned char byte, int sec100 );
  164.     /* write single byte, then poll status register until ready or until
  165.      * timer expires */
  166.  
  167. static int wait_uplink_buffer( int sec100 );
  168.     /* wait for card to provide an uplink buffer; return 0 if there is
  169.      * an uplink buffer avaiable, -1 on timeout */
  170.  
  171. static void sleep_timeout( int sec100 );
  172.     /* sleep for exactly sec100 hundreds of second */
  173.  
  174. static void setup_timeout( int sec100 );
  175.     /* setup timer to be called in sec100 miliseconds; after that period
  176.      * the interrupt function will be called, which will set the timeout
  177.      * variable to -1; the calling function is responsible to delete the
  178.      * timer */
  179.  
  180. static void timer_handler( unsigned long data );
  181.     /* the function to handle event when timer expires */
  182.  
  183. static int base_io = 0x200;
  184.     /* base io address; device needs eight I/O addresses for
  185.      * both channels; the address MUST be dividable by 0x10 */
  186.  
  187. static char *transceiver[32] =
  188. {
  189.     "", "TP/XF-78", "", "TP/XF-1250",
  190.     "FT-10", "TP-RS485-39", "", "RF-10",
  191.     "", "PL-10", "TP-RS485-625", "TP-RS485-1250",
  192.     "TP-RS485-78", "", "", "",
  193.     "PL-20C", "PL-20N", "PL-30", "",
  194.     "", "", "", "",
  195.     "FO-10", "", "", "DC-78",
  196.     "DC-625", "DC-1250", "", ""
  197. };
  198.     /* supported transceiver types */
  199.  
  200. static char *battery[4] =
  201. {
  202.     "fail", "invalid", "low", "ok"
  203. };
  204.     /* battery status - PCNSS card only */
  205.  
  206. static unsigned char clock[32] =
  207. {
  208.     CLK_10, CLK_10, CLK_10, CLK_10,
  209.     CLK_10, CLK_10, CLK_10, CLK_5,
  210.     CLK_10, CLK_10, CLK_10, CLK_10,
  211.     CLK_10, CLK_10, CLK_10, CLK_10,
  212.     CLK_10, CLK_10, CLK_10, CLK_10,
  213.     CLK_10, CLK_10, CLK_10, CLK_10,
  214.     CLK_10, CLK_10, CLK_10, CLK_10,
  215.     CLK_10, CLK_10, CLK_10, CLK_10,
  216. };
  217.     /* clock speeds that should be set up, depending on the transceiver type
  218.      * I make the same for PCNSS card, and hope it's OK */
  219.  
  220. static int major = 40;
  221.     /* major number of device */
  222.  
  223. static struct file_operations pclta_fops =
  224. {
  225.     NULL,        /* lseek() */
  226.     read_pclta,        /* read() */
  227.     write_pclta,    /* write() */
  228.     NULL,        /* readdir() */
  229.     NULL,        /* select() */
  230.     NULL,        /* ioctl() */
  231.     NULL,        /* mmap() */
  232.     open_pclta,        /* open() */
  233.     close_pclta,    /* release() */
  234.     NULL,        /* fsync() */
  235.     NULL,        /* fasync() */
  236.     NULL,        /* check_media_change() */
  237.     NULL        /* revalidate */
  238. };
  239.     /* the structure to be registered */
  240.  
  241. static struct wait_queue *wait_queue;
  242.     /* wait_queue structure to be used in sleep()/wakeup() mechanismus */
  243.  
  244. static struct timer_list timer_list =
  245. {
  246.     NULL, NULL, 0, 0, timer_handler
  247. };
  248.     /* timer list to activate timer */
  249.  
  250. static volatile int timeout;
  251.     /* variable to indicate if timeout occured */
  252.  
  253. #if !defined MODULE
  254. long int
  255. pclta_init( long mem_start, long mem_end )
  256. {
  257.     init_module();
  258.     return mem_start;
  259. }
  260. #endif
  261.  
  262. int
  263. init_module( void )
  264. {
  265.     unsigned char status;
  266.     printk( version );
  267.     if( 0 > check_region( base_io, 8 ) )
  268.     {
  269.     printk( "pclta: unable to get I/O ports %#x-%#x\n", base_io,
  270.         base_io + 7 );
  271.     return -EIO;
  272.     }
  273.  
  274. /* probing for hardware; reset device and then try to receive uplink
  275.  * local reset */
  276.  
  277.     if( inb_p( status_reg ) & RESET )
  278.     {
  279.         outb_p( ( _RESET | CLK_10 ), clkrst_reg );
  280.     }
  281.     else
  282.     {
  283.         if( 0 > write_byte_timeout( CMD_XFER, 100 ) )
  284.         {
  285.             printk( "pcnss: link-layer protocol error "
  286.         "on base I/O address: %#x\n", base_io );
  287.             return -EIO;
  288.         }
  289.             /* test if link-layer write protocol works */
  290.         write_byte_wait( 1 );
  291.         write_byte_wait( niRESET );
  292.             /* send downlink reset */
  293.     }
  294.     /* First, checkout if the card is already in RESET state. It's the
  295.      * case with PCLTA card on power up. If so, then direct the card to
  296.      * get out of reset state. On the other case, we'll first test link-
  297.      * layer protocol, and then send downlink reset */
  298.  
  299.     if( 0 > wait_uplink_buffer( 500 ) )
  300.     {
  301.     printk( "pclta: can't get card from reset state "
  302.         "on base IO address: %#x\n", base_io );
  303.     return -EIO;
  304.     }
  305.     /* here we'll wait to receive uplink local reset */
  306.  
  307. /* the card was found; from this point on, we'll normally
  308.  * communicate with it; there is no further check */
  309.  
  310.     write_byte_wait( CMD_ACK );
  311.     status = read_byte_wait();
  312.     status = read_byte_wait();
  313.     status = read_byte_wait();
  314.     /* read uplink reset */
  315.  
  316.     outb_p( 0x00, selirq_reg );
  317.     /* disable interrupts; it's in the documentation for PCLTA card; I
  318.      * don't know yet how it works for PCNSS card */
  319.  
  320.     write_byte_wait( CMD_XFER );
  321.     write_byte_wait( 2 );
  322.     write_byte_wait( niIRQENA );
  323.     write_byte_wait( IRQPLRTY|RESETE|DLREADYE|DLPBAE|DLBAE|ULREADYE );
  324.     /* now, we'll write to IRQENB internal register to enable all
  325.      * possible interrupts and to set up interrupt line polarity high,
  326.      * which is standard on Intel processors */
  327.  
  328.     write_byte_wait( CMD_XFER );
  329.     write_byte_wait( 1 );
  330.     write_byte_wait( niSSTATUS );
  331.     /* write a command to get transciever status */
  332.  
  333.     if( 0 > wait_uplink_buffer( 100 ) )
  334.     {
  335.     printk( "pclta: no response on status message on "
  336.         "base IO address: %#x\n", base_io );
  337.     return -EIO;
  338.     }
  339.     /* check if the card sent the status message */
  340.  
  341.     write_byte_wait( CMD_ACK );
  342.     status = read_byte_wait(); /* dummy read */
  343.     status = read_byte_wait(); /* length */
  344.     status = read_byte_wait(); /* niSSTATUS */
  345.     status = read_byte_wait(); /* transceiver status */
  346.     if( ! *transceiver[status>>3] )
  347.     {
  348.     printk( "pclta: transceiver not supported\n" );
  349.     return -EIO;
  350.     }
  351.     /* read transceiver and battery status and check out if the
  352.      * transceiver is supported */
  353.  
  354.     outb_p( (_RESET | clock[status>>3] ), clkrst_reg );
  355.     /* setup clock speed based on transceiver status */
  356.  
  357.     if( 0 > register_chrdev( major, "pclta", &pclta_fops ) )
  358.     {
  359.     printk( "pclta: unable to get major number %d\n", major );
  360.     return -EIO;
  361.     }
  362.     /* hardware is successfully installed; register character device */
  363.  
  364.     request_region( base_io, 8, "pclta" );
  365.     /* request I/O region */
  366.  
  367.     printk( "base IO addres: %#x\n", base_io );
  368.     printk( "transceiver: %s\n", transceiver[status>>3] );
  369.     /* print base I/O address, and transceiver status */
  370.  
  371.     printk( "battery: %s\n", battery[status&BATTERY] );
  372.     /* print battery status; it's relevant only for PCNSS module */
  373.  
  374.     return 0;
  375. }
  376.  
  377. #if defined MODULE
  378. void
  379. cleanup_module( void )
  380. {
  381.     release_region( base_io, 8 );
  382.     unregister_chrdev( major, "pclta" );
  383. }
  384. #endif
  385.  
  386. static int
  387. read_pclta( struct inode *inode, struct file *file, char *buf, int count )
  388. {
  389.     unsigned char status, to_read, len, data;
  390.     char *pbuf;
  391.     if( count < 2 || 0 > verify_area( VERIFY_WRITE, buf, count ) )
  392.     return -EFAULT;
  393.     status = inb_p( status_reg );
  394.     if( status & _READY )
  395.     return -EBUSY;
  396.     if( ! ( status & ULREADY ) )
  397.     return -EWOULDBLOCK;
  398.     write_byte_wait( CMD_ACK );
  399.     len = read_byte_wait();
  400.     len = read_byte_wait();
  401.     if( count <= len )
  402.     return -EFAULT;
  403.     pbuf = buf + 1;
  404.     for( to_read = len; to_read; to_read--, pbuf++ )
  405.     {
  406.     data = read_byte_wait();
  407.     put_user( data, pbuf );
  408.     }
  409.     to_read = get_user( buf + 1 );
  410.     put_user( to_read, buf );
  411.     put_user( len - 1, buf + 1 );
  412.     return len + 1;
  413. }
  414.  
  415. static int
  416. write_pclta( struct inode *inode, struct file *file, const char *buf, int count )
  417. {
  418.     unsigned char status, len, ni_q, ni_q_cmd, ni_queue, data;
  419.     if( count < 2 || 0 > verify_area( VERIFY_READ, buf, count ) )
  420.     return -EFAULT;
  421.     ni_q = get_user( buf );
  422.     buf++;
  423.     len = get_user( buf ) + 1;
  424.     buf++;
  425.     if( count <= len )
  426.     return -EFAULT;
  427.     status = inb_p( status_reg );
  428.     if( status & _READY )
  429.     return -EBUSY;
  430.     ni_q_cmd = ni_q & NI_Q_CMD;
  431.     if( ni_q_cmd == niCOMM || ni_q_cmd == niNETMGMT || ni_q == niSERVICE )
  432.     {
  433.     ni_queue = ni_q & NI_QUEUE;
  434.     if( ni_queue == niTQ_P || ni_queue == niNTQ_P )
  435.     {
  436.         if( ! ( status & DLPBA ) )
  437.         return -EWOULDBLOCK;
  438.     } else if( ni_queue == niTQ || ni_queue == niNTQ || ni_q == niSERVICE )
  439.     {
  440.         if( ! ( status & DLBA ) )
  441.         return -EWOULDBLOCK;
  442.     } else
  443.         return -EINVAL;
  444.     }
  445.     write_byte_wait( CMD_XFER );
  446.     write_byte_wait( len );
  447.     write_byte_wait( ni_q );
  448.     for( len--; len; len--, buf++ )
  449.     {
  450.     data = get_user( buf );
  451.     write_byte_wait( data );
  452.     }
  453.     return count;
  454. }
  455.  
  456. static int
  457. open_pclta( struct inode *node, struct file *file )
  458. {
  459.     write_byte_wait( CMD_XFER );
  460.     write_byte_wait( 1 );
  461.     write_byte_wait( niRESET );
  462.     /* send downlink reset */
  463.     MOD_INC_USE_COUNT;
  464.     return 0;
  465. }
  466.  
  467. static void
  468. close_pclta( struct inode *inode, struct file *file )
  469. {
  470.     MOD_DEC_USE_COUNT;
  471. }
  472.  
  473. static unsigned char
  474. read_byte_wait( void )
  475. {
  476.     unsigned char data;
  477.     data = inb_p( data_reg );
  478.     while( inb_p( status_reg ) & _READY );
  479.     return data;
  480. }
  481.  
  482. static void
  483. write_byte_wait( unsigned char byte )
  484. {
  485.     outb_p( byte, data_reg );
  486.     while( inb_p( status_reg ) & _READY );
  487. }
  488.  
  489. static int
  490. write_byte_timeout( unsigned char byte, int sec100 )
  491. {
  492.     outb_p( byte, data_reg );
  493.     setup_timeout( sec100 );
  494.     while( ( inb_p( status_reg ) & _READY ) && ( ! timeout ) );
  495.     del_timer( &timer_list );
  496.     return timeout;
  497. }
  498.  
  499. static int
  500. wait_uplink_buffer( int sec100 )
  501. {
  502.     setup_timeout( sec100 );
  503.     while( ( inb_p( status_reg ) & (_READY | RESET | ULREADY ) ) != ULREADY
  504.            && ( ! timeout ) );
  505.     del_timer( &timer_list );
  506.     return timeout;
  507. }
  508.  
  509. static void
  510. setup_timeout( int sec100 )
  511. {
  512.     timer_list.data = TIMER_TIMEOUT;
  513.     init_timer( &timer_list );
  514.     timer_list.expires = jiffies + sec100 * (HZ/100);
  515.     add_timer( &timer_list );
  516.     timeout = 0;
  517. }
  518.  
  519. static void
  520. sleep_timeout( int sec100 )
  521. {
  522.     timer_list.data = TIMER_SLEEP;
  523.     init_timer( &timer_list );
  524.     timer_list.expires = jiffies + sec100 * (HZ/100);
  525.     add_timer( &timer_list );
  526.     sleep_on( &wait_queue );
  527. }
  528.  
  529. static void
  530. timer_handler( unsigned long data )
  531. {
  532.     switch( data )
  533.     {
  534.         case TIMER_SLEEP:
  535.         del_timer( &timer_list );
  536.         wake_up( &wait_queue );
  537.         return;
  538.     case TIMER_TIMEOUT:
  539.         timeout = -1;
  540.         return;
  541.     }
  542. }
  543.  
  544. /*
  545.  * Local variables:
  546.  *  compile-command: "gcc -Wall -O6 -N -D__KERNEL__ -DMODULE -DLINUX -o pclta.o -c pclta.c"
  547.  *  tab-width: 8
  548.  *  c-indent-level: 4
  549.  * End:
  550.  */
  551.